package com.checksoundtest;

import java.io.File;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.ArrayList;

import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;

import soundanalyzer.SoundAnalyzer;

public class CheckSoundTest {

	//the sample rate of the recording
	static int fs = 8000;
	
	//for calculating the Fourier transform
	static final int N = 2048;
	  
	/**
	  * Calculate sound data (frequency and volume) from an audio file.
	  * 
	  * @param String filename Name of the audio file
	  * @return ArrayList[] result Array of results: first element is an ArrayList of frequencies and second element is an ArrayList of volumes
	  */
	
	public ArrayList[] calcSoundData(String filename)
	{
		//the wav filename
		File fileIn = new File(filename);

		//basic code to read wav file from http://docs.oracle.com/javase/tutorial/sound/converters.html
		try {
		  AudioInputStream audioInputStream = 
		    AudioSystem.getAudioInputStream(fileIn);
		  int bytesPerFrame = 
		    audioInputStream.getFormat().getFrameSize();
		    if (bytesPerFrame == AudioSystem.NOT_SPECIFIED) {
		    // some audio formats may have unspecified frame size
		    // in that case we may read any amount of bytes
		    bytesPerFrame = 1;
		  } 

		  // Set buffer size
		  int numBytes = N * bytesPerFrame; 
		  byte[] audioBytes = new byte[numBytes];
		  try {
		    int numBytesRead = 0;
		    //int numFramesRead = 0;
		    
			//sound analyzer object, that will calculate the fundamental frequency
			SoundAnalyzer soundAnalyzer = new SoundAnalyzer(fs, N);
			//fundamental frequency, to be calculated by sound analyzer
			ArrayList<Float> frequencies = new ArrayList<Float>();
			//volume, to be calculated by sound analyzer
			ArrayList<Float> volumes = new ArrayList<Float>();
			
			int iterationCount = 0;
		    // Try to read numBytes bytes from the file.
		    while ((numBytesRead = 
		      audioInputStream.read(audioBytes)) != -1) {
		      // Calculate the number of frames actually read.
		      //numFramesRead = numBytesRead / bytesPerFrame;

		      // Here, do something useful with the audio data that's 
		      // now in the audioBytes array...
		      //convert the bytes array to a shorts array
		      short[] shorts = new short[audioBytes.length/2];
			  // to turn bytes to shorts as either big endian or little endian. 
			  ByteBuffer.wrap(audioBytes).order(ByteOrder.LITTLE_ENDIAN).asShortBuffer().get(shorts);

			  //calculate Fourier Transform
    	  	  soundAnalyzer.calculateFourierTransform(shorts);
    	  	  //calculate fundamental frequency
	    	  float fBase = soundAnalyzer.calculateFundamentalFrequency();
	    	  frequencies.add(fBase);
	    	  //calculate volume
	    	  float volume = soundAnalyzer.calculateVolume(shorts);
	    	  volumes.add(volume);

	    	  iterationCount++;
		    }

		    ArrayList[] result = new ArrayList[2];
		    result[0] = frequencies;
		    result[1] = volumes;
		    
		    return result;
		    
	    
		  } catch (Exception ex) { 
		    // Handle the error...
			  System.out.println("Error: " + ex.getMessage());
		  }
		} catch (Exception e) {
		  // Handle the error...
			System.out.println("Error: " + e.getMessage());
		}
		
		return null;
	}
	
	/**
	  * Calculate the average value of an ArrayList.
	  * 
	  * @param ArrayList<Float> The array list
	  * @return float The average value
	  */
	
	public float average(ArrayList<Float> list)
	{
	     float average = 0.0f;
	     int count = 0;
	 
	     for (int i = 0; i < list.size(); i++)  {
	    	 if (list.get(i) != 0.0f)
	    	 {
	    		 average += list.get(i) ;
	    		 count ++;
	    	 }
	     }
	     if (count > 0)
	     {
	    	 average = average/count;
	     }
	     return average;
	 }
	
	/**
	  * Main function.
	  * 
	  * Find sound data from several audio files.
	  */
	
	public static void main(String args[]) {
		CheckSoundTest c = new CheckSoundTest();
		
		//test all the available string recordings
		String[] strings = {"g", "d", "e"};
		for (int fileCount = 0; fileCount < 4; fileCount++)
		{
			for (int i = 0; i < 3; i++)
			{
				String string = strings[i];
				System.out.println("Going to test sound file " + string + "" + fileCount + ".wav");
				ArrayList[] result = c.calcSoundData("sounds/"+ string + "" + fileCount + ".wav");
				ArrayList<Float> frequencies = result[0];
				ArrayList<Float> volumes = result[1];
				
				System.out.println("frequencies = "+frequencies);
				System.out.println("volumes = "+volumes);
				System.out.println("average frequency = "+c.average(frequencies));
				System.out.println("average volume = "+c.average(volumes));
				System.out.println("*****");
			}
		}
		
	}
}
